<?php
namespace app\serveruser\logic;

use \app\manage\logic\BaseLogic;

// 用户微应用下的逻辑层
class User extends BaseLogic
{
    protected $name = 'user';
    protected $config = 'db_config_user';
    private $userModel = '\app\serveruser\model\User';
    private $roleModel = '\app\serveruser\model\Role';

    private $tokenLogic = '\app\serveruser\logic\Token';

    use \app\serveruser\traits\Password;

    /*用户登录 自动登录 非自动登录*/
    protected function _login(array $data, bool $is_auto_login = false): array 
    {
        $TokenLogic = $this->logic('\app\serveruser\logic\Token');
        $tokenContent = $TokenLogic->hGetAll(['token'=>$data['token']]);
        if($tokenContent['status'] != SUCCESS_STATUS){
            return $tokenContent;
        }
        // 先根据用户的name || phone 去user表取用户信息 //
        $data['name'] ? $_where['name'] = $data['name'] : null;
        $data['phone'] ? $_where['phone'] = $data['phone'] : null;
        $data['id'] ? $_where['id'] = $data['id'] : null;
        if(!isset($_where)){
            return verify_err(null, '没有找到查询条件id,name,phone');
        }
        $info = $this->model($this->userModel)->where($_where)->find();
        if(!$info){ 
            $this->_addNoUserErrCounts($data, $TokenLogic);//在token中将no_user_err_counts次数加一
            return verify_err(null, '该用户不存在'); 
        }

        //自动登录时，检验登录数据
        if($is_auto_login && ($info['auto_login_token'] != $data['auto_login_token'] || $info['auto_login_time'] != $data['auto_login_time']) ){
            return verify_err(null, '自动登录参数错误！存在账号被窃取的风险');
        }
        $info = $info->toArray();

        //自动登录跳过登录密码检验(不需要输入的密码的为自动登录)
        if(!$is_auto_login){
            $judge = $this->checkLoginPassword($data, $info);
            if(SUCCESS_STATUS !== $judge['status']){ 
                $this->_addNoUserErrCounts($data, $TokenLogic);//在token中将no_user_err_counts次数加一
                return $this->_errLoginAfter($info, $judge['msg'], $tokenContent['res']['no_user_err_counts']);  //执行登录失败后的操作
            }
        }

        unset($info['login_password'], $info['login_salt'], $info['pay_password'], $info['pay_salt']);
        $autoLoginUserInfo = $info;
        unset($info['auto_login_time'], $info['auto_login_token']);
        // 将用户的角色组信息拆分和角色信息合并
        $idsInfo = logic('\app\serveruser\logic\RoleGroup')->roleGroupIdsToRoleIds(['group_ids'=>$info['role_group_ids']]);
        $roleIds = SUCCESS_STATUS === $idsInfo['status'] ? $idsInfo['res']['autoRes'] : '';
        $roleIds .= ',' . $info['role_ids'];
        $roleIds = implode(',', array_unique(explode(',', trim($roleIds, ','))));

        $roleNames = $this->model($this->roleModel)
                         ->where(['id'=>['in', $roleIds],'status'=>'1'])
                         ->column('name');
        // 需要将用户信息保存在redis 的token中
        $addRolesRes =  $this->logic('\app\serveruser\logic\Token')->addRoles(['token'=>$data['token'], 'roles'=>implode(',',$roleNames)]);
        if($addRolesRes['status'] != SUCCESS_STATUS){
            return $this->_errLoginAfter($info, $addRolesRes['msg'], $tokenContent['res']['no_user_err_counts']); //执行登录失败后的操作
        }
        $addInfoRes = $this->logic('\app\serveruser\logic\Token')->hMset(['token'=>$data['token'], 'arr'=>$info]);
        if($addInfoRes['status'] != SUCCESS_STATUS){
            return $this->_errLoginAfter($info, $addInfoRes['msg'], $tokenContent['res']['no_user_err_counts']);  //执行登录失败后的操作
        }
        //登录登录与非自动登录成功后的调用
        if($is_auto_login){
            $info['other_info'] = json_decode($info['other_info'], true);
            return $this->_successAutoLoginAfter($info, $data);
        }else{
            $autoLoginUserInfo['other_info'] = json_decode($autoLoginUserInfo['other_info'], true);
            return $this->_successLoginAfter($autoLoginUserInfo, $data);
        }
    }
    /*用户名不存在或密码输入错误，更新token中的no_user_err_counts字段+1*/
    protected function _addNoUserErrCounts($data, $TokenLogic): array  
    {
        $tokenContent = $TokenLogic->hGetAll(['token'=>$data['token']]);
        if($tokenContent['status'] != SUCCESS_STATUS){
            return $tokenContent;
        }
        $noUserErrCounts = $tokenContent['res']['no_user_err_counts'] + 1;
        $res = $TokenLogic->hMset(['token'=>$data['token'], 'arr'=>['no_user_err_counts'=>$noUserErrCounts]]);
        return $res;
    }
    // 用户登录
    public function login(array $data): array
    {
        return $this->_login($data, false);
    }

    //用户自动登录
    public function autoLogin(array $data): array 
    {
        return $this->_login($data, true);
    }

    //登录失败后的执行方法为：判断是否操作频繁 更新最后错误登录时间 + 错误次数增1
    protected function _errLoginAfter($userInfo, $errMsg, $noUserErrCounts): array 
    {
        if($userInfo['last_err_login_time'] && ( bcsub(NOW, $userInfo['last_err_login_time']) < MAX_LOGIN_RATE )){
            $errMsg = '操作过于频繁，请' . MAX_LOGIN_RATE . '秒之后再试';
        }
        $saveData['login_err_times'] = $userInfo['login_err_times'] + 1;
        $saveData['last_err_login_time'] = NOW;
        $updateRes = $this->model($this->userModel)->save($saveData, ['id'=>$userInfo['id']]);
        $saveData['max_login_err_times'] = MAX_LOGIN_ERR_TIMES;
        $saveData['no_user_err_counts'] = $noUserErrCounts + 1;
        return verify_err($saveData, $errMsg);
    }

    /*非自动登录成功后的执行方法为：错误登录次数、最后错误登录时间分别置0 并返回用户信息
      所有返回用户信息的方法中，除infoAll方法，仅该方法在第一次打勾自动登录时返回了auto_login_token auto_login_time
    */
    protected function _successLoginAfter($userInfo, $data): array 
    {
        $saveData['login_err_times'] = 0;
        $saveData['last_err_login_time'] = 0;
        $saveData['is_auto_login'] = $data['is_auto_login'];
        $saveData['auto_login_time'] = $data['is_auto_login'] ? NOW : 0;
        $saveData['auto_login_token'] = $data['is_auto_login'] ? $data['token'] : '';
        
        $updateRes = $this->model($this->userModel)->save($saveData, ['id'=>$userInfo['id']]);
        if($data['is_auto_login'] && !$userInfo['auto_login_token']){
            $userInfo = array_merge($userInfo, $saveData);
        }else{
            unset($userInfo['auto_login_token'], $userInfo['auto_login_time']);
        }
        return auto_success($userInfo, '登录成功');
    }

    /*自动登录成功后的执行方法*/
    protected function _successAutoLoginAfter($userInfo, $data): array 
    {
        $saveData['login_err_times'] = 0;
        $saveData['last_err_login_time'] = 0;
        $saveData['auto_login_token'] = $data['token'];
        
        $updateRes = $this->model($this->userModel)->save($saveData, ['id'=>$userInfo['id']]);
        unset($userInfo['auto_login_token'], $userInfo['auto_login_time']);
        return auto_success($userInfo, '登录成功');
    }

    //自动登录超时后的处理
    public function autoLoginOvertime($data): array 
    {
        $saveData['is_auto_login'] = 0;
        $saveData['auto_login_time'] = 0;
        $saveData['auto_login_token'] = '';
        $res = $this->model($this->userModel)->save($saveData, ['name'=>$data['name']]);
        return auto_return($res);
    }

    // 用户注册
    public function register(array $data): array
    {
        //注册时判断手机号是否唯一
        $userInfo = $this->model($this->userModel)->where(['phone'=>$data['phone']])->find();
        if($userInfo){
            return verify_err(null, '该手机号已存在'); 
        }
        $checkName = $this->model($this->userModel)->where(['name'=>$data['name']])->find();
        if($checkName){
            return verify_err(null, '该用户名已存在'); 
        }

        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']);
        $data = array_merge($data, $loginPasswordArr);
        $data['role_ids'] = config('append_role_ids');
        $data['role_group_ids'] = config('append_role_group_ids');
        $data['status'] = USER_REGISTER_STATUS;
        $data['update_login_pwd_time'] = NOW;
        $data['update_pay_pwd_time'] = NOW;
        try{
             $res = $this->model($this->userModel)->save($data);
             $res = $this->model($this->userModel)->getLastInsID();
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }

        return auto_return($res, '用户注册成功', '用户注册失败');
    }
    // 根据id name phone 三者之一获取用户信息,不包含密码信息
    public function info(array $data): array
    {
        $_where = make_map($data, ['name', 'id', 'phone']);
        $info = $this->model($this->userModel)
                    ->field('login_password,login_salt,pay_password,pay_salt,auto_login_time,auto_login_token', true)
                    ->where($_where)
                    ->find();
        if(isset($data['is_add_no_user_counts']) && $data['is_add_no_user_counts'] == 1 && !$info){
            $TokenLogic = $this->logic('\app\serveruser\logic\Token');
            $this->_addNoUserErrCounts($data, $TokenLogic);
        }
        if($info){
            $info['other_info'] = json_decode($info['other_info'], true);
            $info['authen_status'] = (int)$info['other_info']['authen_status'];
            $info['authen_status_text'] = $this->_getAuthenStatusText($info['authen_status']);
        }
        return auto_return($info, '成功找到用户信息', '没有找到用户信息');
    }
    // 根据 ID ||用户名 || 手机号 获取某一用户包含自动登录的用户全部信息
    public function infoAll(array $data): array
    {
        $_where = make_map($data, ['name', 'id', 'phone']);
        $info = $this->model($this->userModel)
                    ->field('login_password,login_salt,pay_password,pay_salt', true)
                    ->where($_where)
                    ->find();
        $info && $info['other_info'] = json_decode($info['other_info'], true);
        return auto_return($info, '成功找到用户信息', '没有找到用户信息');
    }
    // 完善用户信息
    public function perfect(array $data): array
    {
        $_where = make_map($data, ['name', 'id', 'phone']);
        $res = $this->model($this->userModel)
                    ->save(['other_info' => $data['other_info']], $_where);
        return auto_return($res, '成功完善用户信息', '完善用户信息失败');
    }
    // 给某一个用户某角色
    public function giveRoles(array $data): array
    {
        // 先查询原来的信息
        $info = $this->info($data);
        if (SUCCESS_STATUS !== $info['status']) {
            return $info;
        }
        $save['role_ids'] = $data['role_id'];
        // 再加新加的角色合并
        if ($info['res']['role_ids']) {
            $oldRoles = explode(',', $info['res']['role_ids']);
            $oldLen = count($oldRoles);
            array_push($oldRoles, $save['role_ids']);
            $newRoles = array_unique($oldRoles);
            if (count($newRoles) === $oldLen) {
                return null_data(null, '用户已有该角色,无需新增');
            }
            sort($newRoles);
            $save['role_ids'] = implode(',', $newRoles);
        }
        // 保存条件
        $_where = make_map($data, ['name', 'id', 'phone']);
        $res = $this->model($this->userModel)
                    ->where($_where)
                    ->update($save);
        return auto_return($res, '成功给某一个用户某些角色','给某一个用户某些角色失败');
    }
    // 移除某用户的某角色
    public function removeUserRole(array $data): array
    {
        // 先查询原来的信息
        $info = $this->info($data);
        if (SUCCESS_STATUS !== $info['status']) {
            return $info;
        }
        $roleIdsArr = array_unique(explode(',', $info['res']['role_ids']));
        $newRoleIdsArr = array_diff($roleIdsArr, [$data['role_id']]);
        sort($newRoleIdsArr);
        $newRoleIds = implode(',', $newRoleIdsArr);
        $_where = \make_map($data, ['id', 'name', 'phone']);
        $res =  $this->model($this->userModel)->save(['role_ids'=>$newRoleIds], $_where);
        return \auto_return($res, '成功移除某用户的某角色', '移除某用户的某角色失败');
    }
    // 用户审核通过
    public function passAudit(array $data): array
    {
        $_where = make_map($data, ['name','id','phone']);
        $res = $this->model($this->userModel)
                    ->save(['status' => '1'], $_where);
        return auto_return($res, '成功用户审核', '用户审核失败');
    }
    // 用户列表
    public function list(array $data): array
    {
        if(isset($data['keywords']) && $data['keywords'] !== ''){
            $_where['id|name|nickname|phone'] = ['like', '%'.$data['keywords'].'%'];
        }
        if(isset($data['authen_status']) && $data['authen_status'] !== ''){
            $_where['other_info$.authen_status'] = (int)$data['authen_status'];
        }
        $_where = $_where ?? true;
        $list = $this->model($this->userModel)
                    ->field('login_password,login_salt,pay_password,pay_salt,auto_login_time,auto_login_token', true)
                    ->where($_where)
                    ->order('id desc')
                    ->paginate($data['list_rows'], false, ['page'=>$data['page']])
                    ->toArray();
        if($list['total'] > 0){
            foreach ($list['data'] as $k => &$v) {
                $v['other_info'] = $other_info = json_decode($v['other_info'], true);
                $v['authen_status'] = (int)$other_info['authen_status'];
                if(isset($other_info['authen_status'])){
                    $v['authen_status_text'] = $this->_getAuthenStatusText($other_info['authen_status']);
                }else{
                    $v['authen_status_text'] = '';
                }
                
            }
        }
        return auto_return_page($list, '成功获取用户列表', '获取用户列表失败');
    }
    // 编辑用户信息
    public function edit(array $data): array
    {
        $save = make_map($data, ['name', 'nickname', 'sex', 'head_portrait', 'phone', 'row_ids','row_group_ids','other_info'], '');
        if(array_eq($save, '')){ return verify_err($save, '至少输入一条要编辑的用户信息'); }
        $res = $this->model($this->userModel)
                    ->save($save, ['id'=>$data['id']]); 
        //更新token里的内容
        if(isset($data['token']) && $data['token']){
            $newUserInfo = $this->model($this->userModel)->where(['id'=>$data['id']])->find();
            if(!$newUserInfo){ return null_data(null, '没有相关用户信息'); }
            $newUserInfo = $newUserInfo->toArray();
            unset($newUserInfo['login_password'], $newUserInfo['login_salt'], $newUserInfo['pay_password'], $newUserInfo['pay_salt'], $newUserInfo['auto_login_token'], $newUserInfo['auto_login_time']);
            $updateTokenRes = $this->logic($this->tokenLogic)->hMset(['token'=>$data['token'], 'arr'=>$newUserInfo]);
        }

        return auto_return($res, '成功编辑用户信息', '编辑用户信息失败');
    }
    // 验证登录密码
    public function checkLoginPassword(array $data): array
    {
        // 查找用户信息
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $info = $this->db()
                    ->field('login_password,login_salt')
                    ->where($_where)
                    ->find();
        if(!$info){ return verify_err(null, '没有相关用户信息'); }
        // 验证登陆密码
        $check = $this->_checkLoginPassword($data['login_password'], $info);
        return auto_return($check, '登陆密码正确', '登陆密码错误');
    }
    // 验证支付密码
    public function checkPayPassword(array $data): array
    {
        // 查找用户信息
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $info = $this->db()
                    ->field('pay_password,pay_salt')
                    ->where($_where)
                    ->find();
        if(!$info){
            return verify_err(null, '没有相关用户信息');
        }else if($info['pay_password'] === ''){
            return verify_err(null, '您还没有设置支付密码');
        }
        // 验证支付密码
        $check = $this->_checkPayPassword($data['pay_password'], $info);
        return auto_return($check, '支付密码正确', '支付密码错误');
    }
    // 修改登录密码
    public function editLoginPassword(array $data): array
    {
        // 验证登录密码
        $checkData = $data;
        $checkData['login_password'] = $data['old_login_password'];
        $checkRes = $this->checkLoginPassword($checkData);
        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
        // 修改登录密码
        $newData = $this->_makeLoginPassword($data['login_password']);
        isset($data['update_login_pwd_time']) && $newData['update_login_pwd_time'] = $data['update_login_pwd_time'];
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $res = $this->db()->where($_where)->update($newData);
        return auto_return($res, '成功修改登录密码', '修改登录密码失败');
    }
    // 修改支付密码
    public function editPayPassword(array $data): array
    {
        // 验证支付密码
        $checkData = $data;
        $checkData['pay_password'] = $data['old_pay_password'];
        $checkRes = $this->checkPayPassword($checkData);
        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
        // 修改支付密码
        $newData = $this->_makePayPassword($data['pay_password']);
        isset($data['update_pay_pwd_time']) && $newData['update_pay_pwd_time'] = $data['update_pay_pwd_time'];
        $_where = make_map($data, ['name','id','phone']);
        $_where['status'] = '1';
        $res = $this->db()->where($_where)->update($newData);
        return auto_return($res, '成功修改支付密码', '修改支付密码失败');
    }
    // 初始化用户支付密码 在用户没有设置支付密码的情况下
    public function initPayPassword(array $data): array
    {
        // 先验证登录密码是否正确
        $checkRes = $this->checkLoginPassword($data);
        if(SUCCESS_STATUS !== $checkRes['status']){ return $checkRes; }
        // 先查询用户的是否设置过支付密码
        $_where = make_map($data, ['name','id','phone']);
        $payPassword = $this->db()->where($_where)->value('pay_password');
        if('' !== $payPassword){ return verify_err(null, '已存在支付密码不能初始化'); }
        // 把空密码也作为where条件之一
        $_where['status'] = '1';
        $_where['pay_password'] = '';
        $payPasswordArr = $this->_makePayPassword($data['pay_password']);
        $res = $this->model($this->userModel)
                    ->where($_where)
                    ->update($payPasswordArr);
        return auto_return($res, '成功初始化用户支付密码', '初始化用户支付密码失败');
    }
    // 重置用户登录密码-中间层验证手机验证码通过后再调用本方法
    public function resetLoginPassword(array $data, bool $resetUser = true): array
    {
        // 先判断用户是否存在
        $findInfo = $this->info($data);
        if(SUCCESS_STATUS !== $findInfo['status']){ return $findInfo; }
        if ($resetUser && $findInfo['res']['id'] <= MAX_SYSTEM_ID) {
            return verify_err($findInfo['res']['id'], '无权重置管理员帐户' . $findInfo['res']['name']);
        }
        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']);
        $_where = make_map($data, ['name','id','phone']);
        $res = $this->model($this->userModel)
                    ->where($_where)
                    ->update($loginPasswordArr);
        return auto_return($res, '成功重置用户登录密码', '重置用户登录密码失败');
    }
    // 重置用户支付密码-中间层验证手机验证码通过后再调用本方法
    public function resetPayPassword(array $data, bool $resetUser = true): array
    {
        // 先判断用户是否存在
        $findInfo = $this->info($data);
        if(SUCCESS_STATUS !== $findInfo['status']){ return $findInfo; }
        if ($resetUser && $findInfo['res']['id'] <= MAX_SYSTEM_ID) {
            return verify_err($findInfo['res']['id'], '无权重置管理员帐户' . $findInfo['res']['name']);
        }
        $payPasswordArr = $this->_makePayPassword($data['pay_password']);
        $_where = make_map($data, ['name','id','phone']);
        $res = $this->model($this->userModel)
                    ->where($_where)
                    ->update($payPasswordArr);
        return auto_return($res, '成功重置用户支付密码', '重置用户支付密码失败');
    }
    // 根据用户传入的IDS获取用户信息
    public function infoByIds(array $data): array
    {
        $len = count(explode(',', $data['ids']));

        $_where['id'] = ['in', $data['ids']];
        $_where['status'] = '1';
        $res = $this->model($this->userModel)
                    ->field('login_password,login_salt,pay_password,pay_salt,auto_login_time,auto_login_token', true)
                    ->where($_where)
                    ->select();
        $resLen = count($res);
        if ($len === $resLen) {
            return auto_success($res, '成功获取相关用户信息');
        } else {
            return auto_failure($res, '查询' . $len . '个id,获取' . $resLen . '条用户信息');
        }
    }
    // 用户退出登录
    public function logout(array $data): array
    {
        $deleteRes =  logic('\app\serveruser\logic\Token')->delete($data);
        return $deleteRes['status'] === SUCCESS_STATUS
            ? \auto_success(null, '用户退出登录成功')
            : \auto_failure(null, '用户退出登录失败:' . $deleteRes['msg'] . '或token不存在');
    }
    // 用户更改自己的信息
    public function editSelfInfo(array $data): array
    {
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }

        // 将相关信息保存到数据库
        $newData = make_map($data, ['nickname', 'sex', 'head_portrait'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['token'] = $data['token'];
        $res = $this->edit($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的信息成功') :  auto_failure(null, '用户更改自己的信息失败');
    }
    // 用户更改自己的登录密码
	public function editSelfLoginPassword(array $data): array
	{
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }
		// 将相应信息发送给相关接口
        $newData = make_map($data, ['login_password', 'old_login_password', 're_login_password'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['update_login_pwd_time'] = NOW;
        $res = $this->editLoginPassword($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的登录密码成功') :  auto_failure(null, '用户更改自己的登录密码失败');
	}
    // 管理员重置普通用户密码
    public function resetUserLoginPassword(array $data): array
    {
        return $this->resetLoginPassword($data, true);
    }
    // 超级管理员重置所有用户密码的接口
    public function resetAllLoginPassword(array $data): array
    {
        return $this->resetLoginPassword($data, false);
    }
    // 用户更改自己的支付密码
    public function editSelfPayPassword(array $data): array
    {
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }
        // 将相应信息发送给相关接口
        $newData = make_map($data, ['pay_password', 'old_pay_password', 're_pay_password'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['update_pay_pwd_time'] = NOW;
        $res = $this->editPayPassword($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的支付密码成功') :  auto_failure(null, '用户更改自己的支付密码失败:' . $res['msg']);
    }
    // 管理员重置普通用户支付密码
    public function resetUserPayPassword(array $data): array
    {
        return $this->resetPayPassword($data, true);
    }
    // 管理员重置所有用户支付密码
    public function resetAllPayPassword(array $data): array
    {
        return $this->resetPayPassword($data, false);
    }

    //用户更改自己的用户基本信息
    public function updateUserInfo(array $data): array
    {
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }

        $userInfo = $this->db()->where(['id'=>$tokenRes['res']['id']])->find();
        $other_info = json_decode($data['other_info'], true);
        $db_other_info = json_decode($userInfo['other_info'], true);
        $authen_status = $db_other_info['authen_status'] ?? '-1';
        if(isset($other_info['real_name']) && in_array($authen_status,['0','1']) && $other_info['real_name'] != $db_other_info['real_name'] ){
            return verify_err(null, '真实姓名请和实名认证时的姓名保持一致！');
        }
        isset($other_info['birthday']) && $db_other_info['birthday'] = $other_info['birthday'];
        isset($other_info['email']) && $db_other_info['email'] = $other_info['email'];
        isset($other_info['real_name']) && $db_other_info['real_name'] = $other_info['real_name'];

        // 将相关信息保存到数据库
        $newData = make_map($data, ['nickname', 'sex', 'head_portrait'], '');
        $newData['other_info'] = json_encode($db_other_info);
        $newData['id'] = $tokenRes['res']['id'];
        $newData['token'] = $data['token'];
        $res = $this->edit($newData);
        return $res['status'] ? auto_success($res['res'], '用户更改自己的信息成功') :  auto_failure(null, '用户更改自己的信息失败');
    }

    //用户进行实名认证
    public function authentication(array $data): array
    {
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }
        $other_info = json_decode($tokenRes['res']['other_info'], true);
        if(in_array($other_info['authen_status'], ['0','1'])){
            return verify_err(null, '您已提交过认证信息');
        }

        $authentication['id_number'] = $data['id_number'];
        $authentication['front_img'] = $data['front_img'];
        $authentication['back_img'] = $data['back_img'];
        $authentication['create_time'] = NOW;
        $authentication['update_time'] = NOW;
        $new_other_info['authentication'] = $authentication;
        $new_other_info['authen_status'] = 0;  // 认证状态 -1 未提交 0 待审核 1 审核通过 2 审核失败
        $new_other_info['real_name'] = $data['real_name'];
        $data['other_info'] = json_encode(array_merge($other_info, $new_other_info));
        $data['id'] = $tokenRes['res']['id'];
        $res = $this->edit($data);
        if($res['status'] != SUCCESS_STATUS){
            return auto_failure(null, '提交认证信息失败');
        }
        return auto_success($res['res'], '提交认证信息成功');

    }
    /*用户进行换绑手机*/
    public function changePhone(array $data): array
    {
        // 根据token找到用户的ID
        $tokenRes = $this->logic($this->tokenLogic)->hGetAll($data);
        if(SUCCESS_STATUS !== $tokenRes['status']){
            return $tokenRes;
        } else if (!isset($tokenRes['res']['id'])) {
            return verify_err(null, '此token没有找到相关用户ID');
        }

        $newData = make_map($data, ['phone'], '');
        $newData['id'] = $tokenRes['res']['id'];
        $newData['token'] = $data['token'];
        try{
            $res = $this->edit($newData);
        }catch(\Exception $e){
            return server_err(null, '数据库错误' . $e->getMessage() );
        }
        return $res['status'] ? auto_success($res['res'], '换绑手机号成功') :  auto_failure(null, '换绑手机号失败');
    }

    /*管理员审核用户的实名认证信息*/
    public function verifyAuthentication(array $data): array
    {
        $_where['id'] = $data['id'];
        $_where['status'] = 1;
        $userInfo = $this->model($this->userModel)->where($_where)->find();
        if(!$userInfo){
            return auto_failure(null, '该用户信息不存在');
        }
        $other_info = json_decode($userInfo['other_info'], true);
        if(!isset($other_info['authen_status']) && $other_info['authen_status'] != 0){
            return auto_failure(null, '该用户未提交实名认证信息');
        }

        $other_info['authen_status'] = $data['status'];
        $saveData['other_info'] = json_encode($other_info);
        $res = $this->model($this->userModel)->save($saveData, $_where);

        return auto_return($res);
    }

    /*获取不同状态下的实名认证列表*/
    public function getAuthticationList($data): array
    {
        $_where['status'] = 1;
        $_where['other_info$.authen_status'] = $data['status'];
        $data['keywords'] && $_where['name|nickname|other_info$.real_name|other_info$.authentication.id_number'] = ['like', '%' . $data['keywords'] . '%'];
        $list = $this->db()
                    ->field(['id','name','nickname','sex','head_portrait','phone','other_info','other_info$.authen_status'=>'other_info_authen_status','other_info$.authentication'=>'other_info_authentication'])
                    ->where($_where)
                    ->order(['other_info$.authentication.create_time'=>'desc'])
                    ->paginate($data['list_rows'], false, ['page'=>$data['page']])
                    ->toArray();
        if($list['total'] > 0){
            foreach ($list['data'] as $k => &$v) {
                $v['other_info'] = json_decode($v['other_info'], true);
                $v['other_info_authentication'] = json_decode($v['other_info_authentication'], true);
                $v['other_info_authentication']['create_time'] && $v['other_info_authentication']['create_time'] = date('Y-m-d', $v['other_info_authentication']['create_time']);
                $v['other_info_authentication']['update_time'] && $v['other_info_authentication']['update_time'] = date('Y-m-d', $v['other_info_authentication']['update_time']);
                $v['other_info_authen_status_text'] = $this->_getAuthenStatusText($v['other_info_authen_status']);
            }
        }
        return auto_return_page($list, '成功获取实名认证列表', '获取实名认证列表失败');
    }

    //这里用于获取实名认证的状态文字
    private function _getAuthenStatusText($authen_status): string 
    {
        $authen_status_text = '';
        if($authen_status == -1){
            $authen_status_text = '未提交';
        }elseif($authen_status == 0){
            $authen_status_text = '待审核';
        }elseif($authen_status == 1){
            $authen_status_text = '审核通过';
        }elseif($authen_status == 2){
            $authen_status_text = '审核失败';
        }else{
            $authen_status_text = '未知错误';
        }
        return $authen_status_text;
    }

    /*获取我的账户安全级别 添加两个字段 最后一次修改登录密码的时间 最后一次修改支付密码的时间*/
    public function getSecurityLevel($data): array 
    {
        $level_text = '中等';
        $isAutonym = false;
        $_where['id'] = $data['user_id'];
        $_where['status'] = 1;
        $userInfo = $this->model($this->userModel)->where($_where)->find();
        $other_info = json_decode($userInfo['other_info'], true);
        if(isset($other_info['authen_status']) && $other_info['authen_status'] == 1){ 
            $isAutonym = true;   //是否进行了实名认证的标识
        }
        $loginMsg = bcsub(NOW,$userInfo['update_login_pwd_time']) > 86400 ? '您已超过一个月未更换密码，建议您定期更改密码以保护账户安全' : '互联网账号存在被盗风险，建议您定期更改密码以保护账户安全';
        $isUpdatePayPwd = $userInfo['update_pay_pwd_time'] ? true : false;   //是否修改了支付密码
        $payPwdMsg = $isUpdatePayPwd ? '建议您定期更改支付密码以保护账户安全' : '您的支付密码仍为初始密码，建议更改支付密码以保护账户安全';
        if($isUpdatePayPwd && $isAutonym){
            $level_text = '较高';
        }elseif(!$isUpdatePayPwd && !$isAutonym){
            $level_text = '较低';
        }
        $res['level_text'] = $level_text;
        $res['is_autonym'] = $isAutonym;
        $res['is_updatePayPwd'] = $isUpdatePayPwd;
        $res['login_msg'] = $loginMsg;
        $res['pay_pwd_msg'] = $payPwdMsg;
        return auto_return($res, '成功获取我的账户安全级别', '获取我的账户安全级别失败');
    }

    /*获取最近一周的用户增量和用户总数%y-%m-%d*/
    public function userIncreTendency($data): array 
    {
        $dbDateFormat = $data['dbDateFormat'];
        $Db = \think\Db::connect(config('db_config_user'));
        $weekSql = "select count(*) as counts, FROM_UNIXTIME(create_time, '$dbDateFormat') as create_time_date from tp_user where create_time > UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 1 WEEK)) group by create_time_date";
        $queryRes = $Db->query($weekSql);
        $weeks = week_key_array($data['dateFormat']);
        $delQueryRes = [];
        foreach ($queryRes as $k => $v) {
            $delQueryRes[$v['create_time_date']] = $v['counts'];
        }
        $weekIncre = array_merge($weeks, $delQueryRes);
        $newWeekIncre = [];
        foreach ($weekIncre as $k => $v) {
            $one['date'] = $k;
            $one['value'] = $v;
            $newWeekIncre[] = $one;
        }
        $res['weekIncre'] = $newWeekIncre;
        $res['total'] = $this->db()->count();
        return auto_return($res);
    }
    // 后台添加管理员
    public function addManager($data): array 
    {
        //注册时判断手机号是否唯一
        $userInfo = $this->model($this->userModel)->where(['phone'=>$data['phone']])->find();
        if($userInfo){
            return verify_err(null, '该手机号已存在'); 
        }
        $checkName = $this->model($this->userModel)->where(['name'=>$data['name']])->find();
        if($checkName){
            return verify_err(null, '该用户名已存在'); 
        }

        $loginPasswordArr = $this->_makeLoginPassword($data['login_password']);
        $data = array_merge($data, $loginPasswordArr);
        $data['other_info'] = json_encode(['authen_status'=>-1]);  //未提交实名认证
        $data['role_ids'] = config('append_role_ids');
        $data['role_group_ids'] = config('append_role_group_ids');
        $data['status'] = USER_REGISTER_STATUS;
        $data['update_login_pwd_time'] = NOW;
        $data['update_pay_pwd_time'] = NOW;
        // 获取管理员id
        $maxId = $this->model($this->userModel)->where(['id'=>['lt', 1000]])->max('id');
        $data['id'] = $maxId + 1;
        try{
             $res = $this->model($this->userModel)->save($data);
             $res = $this->model($this->userModel)->getLastInsID();
        }catch (\Exception $e) {
            // 当唯一键重复等报错时
            return server_err(null, '数据库异常:' . $e->getMessage());
        }

        return auto_return($res, '用户注册成功', '用户注册失败');
    }
    
}
